import logging
import time
from typing import Dict, Any, Optional
from datetime import datetime
import json

class ClusterMonitor:
    def __init__(self, log_file: str = 'logs/cluster_operations.log'):
        # 配置日志记录
        self.logger = self._setup_logger(log_file)
        self.metrics_history: Dict[str, list] = {
            'hdfs': [],
            'yarn': [],
            'spark': [],
            'flink': []
        }
    
    def _setup_logger(self, log_file: str) -> logging.Logger:
        """设置日志记录器"""
        logger = logging.getLogger('ClusterMonitor')
        logger.setLevel(logging.INFO)
        
        # 创建文件处理器
        fh = logging.FileHandler(log_file)
        fh.setLevel(logging.INFO)
        
        # 创建控制台处理器
        ch = logging.StreamHandler()
        ch.setLevel(logging.INFO)
        
        # 创建格式化器
        formatter = logging.Formatter(
            '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
        )
        fh.setFormatter(formatter)
        ch.setFormatter(formatter)
        
        # 添加处理器到日志记录器
        logger.addHandler(fh)
        logger.addHandler(ch)
        
        return logger
    
    def log_operation(self, operation: str, details: Dict[str, Any],
                      status: str = 'success') -> None:
        """记录集群操作"""
        log_entry = {
            'timestamp': datetime.now().isoformat(),
            'operation': operation,
            'details': details,
            'status': status
        }
        
        if status == 'success':
            self.logger.info(json.dumps(log_entry))
        else:
            self.logger.error(json.dumps(log_entry))
    
    def record_metrics(self, component: str, metrics: Dict[str, Any]) -> None:
        """记录组件指标"""
        metric_entry = {
            'timestamp': datetime.now().isoformat(),
            'metrics': metrics
        }
        
        self.metrics_history[component].append(metric_entry)
        
        # 保持历史记录在合理范围内
        if len(self.metrics_history[component]) > 1000:
            self.metrics_history[component] = self.metrics_history[component][-1000:]
    
    def get_metrics_history(self, component: str,
                           start_time: Optional[datetime] = None,
                           end_time: Optional[datetime] = None) -> list:
        """获取指定时间范围内的指标历史"""
        if component not in self.metrics_history:
            return []
        
        if not (start_time or end_time):
            return self.metrics_history[component]
        
        filtered_metrics = []
        for metric in self.metrics_history[component]:
            metric_time = datetime.fromisoformat(metric['timestamp'])
            if start_time and metric_time < start_time:
                continue
            if end_time and metric_time > end_time:
                continue
            filtered_metrics.append(metric)
        
        return filtered_metrics
    
    def alert(self, component: str, message: str,
              level: str = 'warning') -> None:
        """发送告警信息"""
        alert_entry = {
            'timestamp': datetime.now().isoformat(),
            'component': component,
            'message': message,
            'level': level
        }
        
        if level == 'warning':
            self.logger.warning(json.dumps(alert_entry))
        elif level == 'error':
            self.logger.error(json.dumps(alert_entry))
        elif level == 'critical':
            self.logger.critical(json.dumps(alert_entry))
    
    def monitor_job_progress(self, job_id: str,
                            get_status_func: callable,
                            interval: int = 60,
                            timeout: Optional[int] = None) -> None:
        """监控作业进度
        
        Args:
            job_id: 作业ID
            get_status_func: 获取作业状态的函数
            interval: 检查间隔（秒）
            timeout: 超时时间（秒），None表示无限期监控
        """
        start_time = time.time()
        while True:
            try:
                status = get_status_func(job_id)
                self.log_operation(
                    'job_status_check',
                    {'job_id': job_id, 'status': status}
                )
                
                # 检查作业是否完成
                if status.get('state') in ['FINISHED', 'FAILED', 'KILLED']:
                    break
                
                # 检查是否超时
                if timeout and (time.time() - start_time) > timeout:
                    self.alert(
                        'job_monitor',
                        f'Job {job_id} monitoring timed out after {timeout} seconds',
                        'warning'
                    )
                    break
                
                time.sleep(interval)
                
            except Exception as e:
                self.alert(
                    'job_monitor',
                    f'Error monitoring job {job_id}: {str(e)}',
                    'error'
                )
                break